#include <iostream>
#include <cstring>
using namespace std;

const int N = 510;              //某一组的点的点的数目是510
const int M = 100010;           //有100000条边
int h[N], e[M], ne[M], idx = 0; //邻接表
int p[N];                       //第二组的点对于第一组的配队
bool st[N];                     //记录这个点本次遍历中是否已经找到了
int n1, n2, m, u, v;            //获取输入
int res = 0;                    //存储答案，每配队成功一对，就加上一

void add(int a, int b)
{
    e[idx] = b;
    ne[idx] = h[a];
    h[a] = idx++;
    return;
}

bool find(int u) //判断点u是否能在现阶段还没遍历的点里面找到配队的点
{
    for (int i = h[u]; i != -1; i = ne[i]) //遍历所有可能可以和这点配队的点
    {
        int j = e[i];
        if (!st[j]) //如果这个点本次已经被遍历过了
        {
            st[j] = true; //将这个点标记为已遍历
            if (!p[j])    //如果这个点没有队友
            {
                p[j] = u;    //那么他现在就是点u的队友了
                return true; //找到队友之后就返回
            }
            else if (find(p[j])) //尝试给j的队友找新队友
            {
                p[j] = u; //他对象找到新对象以后，我就是他的新对象了
                return true;
            }
        }
    }
    return false;
}

int main()
{
    memset(h, -1, sizeof h); //初始化邻接表
    memset(p, 0, sizeof p);  //现阶段都没有同伴
    cin >> n1 >> n2 >> m;
    while (m--)
    {
        cin >> u >> v;
        add(u, v);
    }
    for (int i = 1; i <= n1; ++i) //遍历所有第一组的点，给他们中的每一个都尝试找到一个同伴
    {
        memset(st, false, sizeof st); //清空这一轮的第二组的遍历
        if (find(i))
            res++;
    }
    cout << res;
    return 0;
}